﻿using HAF.Core.Enums;
using HAF.Dispatcher.Enum;
using HAF.Dispatcher.WorkItem;
using HAF.LogUtility;
using HAF.LogUtility.Assistantor;
using HAF.LogUtility.Enum;
using HAF.LogUtility.Except;
using HAF.LogUtility.Model;
using RDS.Core.Utils;
using System;
using System.IO;

namespace RDS.Core
{
    /// <summary>
    /// RDS插件工作项基类
    /// </summary>
    public class PluginWorkItem : PushMessageable, IWorkItem, IDisposable
    {
        #region 公用属性字段
        /// <summary>
        /// 工作项编号
        /// </summary>
        public int ID { get; set; }
        /// <summary>
        /// 标识
        /// </summary>
        public string Tag { get; set; }
        /// <summary>
        /// 归属任务编号
        /// </summary>
        /// <remarks>默认使用GUID值</remarks>
        public string TaskID { get; set; } = Guid.NewGuid().ToString("N");
        /// <summary>
        /// 工作项名称
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 工作项展示名称
        /// </summary>
        public string Caption { get; set; }
        /// <summary>
        /// 工作项优先级
        /// </summary>
        public int Priority { get; set; }
        /// <summary>
        /// 运行模式
        /// </summary>
        public EnumItemModel Model { get; set; } = EnumItemModel.Multi;
        /// <summary>
        /// 工作项动作
        /// </summary>
        public int WorkAction { get; set; }
        /// <summary>
        /// 工作项归属分组
        /// </summary>
        public int WorkGroup { get; set; }
        /// <summary>
        /// 任务类型 此处和分组有什么区别？
        /// </summary>
        public int WorkType { get; set; } = 0;
        /// <summary>
        /// 工作项状态
        /// </summary>
        public EnumRunItemStatu Statu { get; set; } = EnumRunItemStatu.Waiting;
        /// <summary>
        /// 任务状态
        /// </summary>
        public int TaskState { get; set; }
        /// <summary>
        /// 工作项轮询时长
        /// </summary>
        public int Times { get; set; }
        /// <summary>
        /// 工作项失败已重试次数
        /// </summary>
        /// <remarks>原定义为可重试次数，现更改为已重试次数，每个工作项可重试次数由主配置决定，自己不再配置</remarks>
        public int RedoTimes { get; set; }
        /// <summary>
        /// 工作项关联编号 
        /// </summary>
        /// <remarks>主要用于关联入参表和出参表，也常用于日志输出文件名称前缀</remarks>
        public string WorkID { get; set; }
        /// <summary>
        /// 工作项内容（对象）
        /// </summary>
        public object WorkItems { get; set; }
        /// <summary>
        /// 工作项内容（文本）
        /// </summary>
        public string WorkJson { get; set; }
        /// <summary>
        /// 自动保存 
        /// </summary>
        /// <remarks>在多个工作项同步工作时需配置为false</remarks>
        public bool AutoSave { get; set; }
        /// <summary>
        /// 工作项创建人
        /// </summary>
        public string CreateUser { get; set; } = "WedoIptv";
        /// <summary>
        /// 工作项创建时间
        /// </summary>
        public DateTime CreateTime { get; set; } = DateTime.Now;
        /// <summary>
        /// 工作项开始时间
        /// </summary>
        public DateTime BeginTime { get; set; } = DateTime.Now;
        /// <summary>
        /// 工作项结束时间
        /// </summary>
        public DateTime EndTime { get; set; } = DateTime.Now;
        /// <summary>
        /// 是否支持远程执行
        /// </summary>
        public bool AllowRemoteExec { get; set; } = false;
        /// <summary>
        /// 远程执行地址
        /// </summary>
        public string HostHandle { get; set; }
        /// <summary>
        /// 执行方法
        /// </summary>
        public EnumHttpMethod Method { get; set; } = EnumHttpMethod.POST;
        #endregion 公用属性字段

        /// <summary>
        /// 资源释放
        /// </summary>
        public void Dispose()
        {
            this.Statu = EnumRunItemStatu.End;
            WriteDebugMessage("Work对象{0}释放", Name);
        }

        /// <summary>
        /// 资源重置
        /// </summary>
        public void Reset()
        {
            WorkItems = null;
            this.Statu = EnumRunItemStatu.Begin;
            WriteDebugMessage("Work对象{0}重置", Name);
        }

        /// <summary>
        /// 回调指令
        /// </summary>
        public Action<Object, WorkOutMessage> CallBack { get; set; }
        /// <summary>
        /// 工作项执行指令
        /// </summary>
        public virtual void ExecItem()
        {
            LogOutName = string.IsNullOrEmpty(WorkID) ? TaskID : WorkID;
            WriteInfoMessage("工作项 TaskID {0} TaskName {1} WorkID {2} 启动", TaskID, string.IsNullOrEmpty(this.Caption) ? this.Name : this.Caption, WorkID);

            this.Statu = HAF.Dispatcher.Enum.EnumRunItemStatu.Exec;
        }

        /// <summary>
        /// 更新任务状态
        /// </summary>
        /// <param name="taskId">任务编号</param>
        /// <param name="iState">状态</param>
        public virtual void UpdateTaskState(string taskId, int iState)
        {
            if (string.IsNullOrEmpty(taskId))
            {
                throw new RunException(RunCode.ParamsCheckError);
            }
        }

        /// <summary>
        /// 工作项结果集
        /// </summary>
        public object ResultItems { get; set; }

        /// <summary>
        /// 执行回馈消息
        /// </summary>
        public WorkOutMessage OutMessage { get; set; } = new WorkOutMessage();

        /// <summary>
        /// 工作项回调函数
        /// </summary>
        protected void ReturnItem()
        {
            if (CallBack != null)
            {
                OutMessage.ID = this.ID.ToString();
                OutMessage.Code = 0;
                OutMessage.Message = string.Format("采集服务：{0}工作项完成", string.IsNullOrEmpty(this.Caption) ? this.Name : this.Caption);
                CallBack(ResultItems, OutMessage);
            }

            //写SysMonitor系统日志
            WriteInfoMessage("采集服务：{0}工作项完成", string.IsNullOrEmpty(this.Caption) ? this.Name : this.Caption);
            //LogHelper.WriteInfoLog(string.Format("采集服务：{0}工作项完成", string.IsNullOrEmpty(this.Caption) ? this.Name : this.Caption));
        }

        /// <summary>
        /// 添加推送消息
        /// </summary>
        /// <param name="msg"></param>
        public void AddOutMessage(string msg)
        {
            //if (OutMessage.MessageSet == null)
            //{
            //    OutMessage.MessageSet = new List<string>();
            //}
            //if (!string.IsNullOrEmpty(msg))
            //{
            //    OutMessage.MessageSet.Add(msg);
            //}
        }

        #region 日志上报实现
        /// <summary>
        /// 日志上报实现
        /// </summary>
        /// <param name="head">工单流水号</param>
        /// <param name="msg">下载结果</param>
        /// <param name="type">日志类型</param>
        protected void PushLog(string head, string msg, EnumLogLevel type)
        {
            try
            {
                if (RuntimeAdapter.AllowReportLog)
                {
                    //WriteDebugMessageExt(head, "启动{0}日志上报，内容为：{1}", type.ToString(), msg);
                    ShowDebugMessageExt(head, "启动{0}日志上报，内容为：{1}", type.ToString(), msg);
                    Loginfo log = new Loginfo() { SamName = RuntimeAdapter.HostName, LogType = type, Head = head, Message = msg };
                    string rtnMsg = WebHelper.GetHttpResponse(RuntimeAdapter.LogEngine, "POST", JsonAssistant.Serialize(log));
                }
            }
            catch (Exception ex)
            {
                ShowErrMessageExt(head, "日志上报异常：{0}", ex.ToString());
            }

        }
        #endregion 日志处理

        #region 任务响应
        protected void NotifyTaskErr(string errStr, int errValue = (int)EnumRunItemStatu.Error, string postUrl = "")
        {
            WriteErrMessageExt(LogOutName, "任务{0}执行失败, 错误信息为{1}", TaskID, errStr);

            OutMessage.Code = errValue;
            OutMessage.Message = errStr;

            ShowErrMessage(errStr);
            TaskNotify(OutMessage, postUrl);
        }

        /// <summary>
        /// 任务回执
        /// </summary>
        /// <param name="responseMsg">响应对象</param>
        /// <param name="postUrl">远端回执地址</param>
        protected void TaskNotify(WorkOutMessage responseMsg, string postUrl = "")
        {
            try
            {
                //回执数据
                TaskResponse returnTask = new TaskResponse()
                {
                    TaskID = this.TaskID,
                    TaskType = EnumRunTaskType.Transfer,
                    Statu = responseMsg.Code != 200 ? (int)EnumRunTaskStatu.Error : (int)EnumRunTaskStatu.End,
                    Comment = responseMsg.Message,
                    Token = responseMsg.Token,
                    ReturnValues = responseMsg
                };

                EndTopTask(TaskID, responseMsg.Code == 200 ? 5 : -1);

                //通过ToString方式进行序列化
                //string retContent = returnTask.ToString();
                string content = JsonAssistant.Serialize(returnTask);
                string remoteUrl = string.IsNullOrEmpty(postUrl) ? RuntimeAdapter.WasNotifyUrl : postUrl;
                ShowDebugMessageExt(OutMessage.ID, "当前工单{0}提交迁移任务回馈到{1}，内容为{2}", TaskID, remoteUrl, JsonAssistant.SerializeAscii(returnTask));
                string rtnMsg = WebHelper.GetHttpResponse(remoteUrl, "POST", content);
            }
            catch (Exception ex)
            {
                ShowErrMessage("任务{0}响应失败{1}", TaskID, ex.Message);
            }
            finally
            {
                this.Statu = (EnumRunItemStatu)responseMsg.Code;
            }
        }
        #endregion 任务响应

        #region 前端任务处理
        /// <summary>
        /// 更新前端任务列表基础数据
        /// </summary>
        /// <param name="correlateId"></param>
        /// <param name="tag"></param>
        /// <param name="siteName"></param>
        protected void UpdateTopTaskInfo(string correlateId, string tag, string siteName)
        {
            //通过任务编号找到缓存中执行的任务数据
            var runTaskItem = RuntimeAdapter.Tasks.Find(t => t.ID == TaskID);
            if (runTaskItem != null)
            {
                runTaskItem.Comment = correlateId; // itemCfg.FileSets[0].Group;
                runTaskItem.Tag = correlateId; // itemCfg.Tag;
                runTaskItem.Name = siteName; // itemCfg.Site;
            }
        }

        /// <summary>
        /// 前端任务状态更新
        /// </summary>
        /// <param name="taskid"></param>
        /// <param name="value"></param>
        protected void UpdateTopTaskState(string taskid, int value)
        {
            var runTaskItem = RuntimeAdapter.Tasks.Find(t => t.ID == taskid);
            if (runTaskItem != null)
            {
                runTaskItem.State = value;
            }
            //RuntimeAdapter.Tasks.Find(t => t.ID == TaskID).State = value;
        }
        /// <summary>
        /// 前端任务结束
        /// </summary>
        /// <param name="taskid"></param>
        /// <param name="value"></param>
        protected void EndTopTask(string taskid, int value)
        {
            //两种方式写前台监控队列的值
            RuntimeAdapter.Tasks.ForEach(delegate (RunTask t) { if (t.ID == TaskID) { t.State = value; t.EndTime = DateTime.Now; } });
            //RuntimeAdapter.Tasks.Find(t => t.ID == TaskID).State = responseMsg.Code;
            //RuntimeAdapter.Tasks.Find(t => t.ID == TaskID).EndTime = DateTime.Now;
            this.Statu = EnumRunItemStatu.End;
        }
        #endregion 前端任务处理

        /// <summary>
        /// 刷新插件配置
        /// </summary>
        /// <typeparam name="T">配置对象类型</typeparam>
        /// <param name="configName">配置文件名称</param>
        /// <returns></returns>
        protected T RefreshPluginConfig<T>(string configName)
        {
            //获取本地配置文件 每次执行的时候读取，实现热配置
            string loadConfigPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, RuntimeAdapter.ConfigDir, configName);
            if (File.Exists(loadConfigPath))
            {
                T _runConfig = JsonAssistant.FromFile<T>(loadConfigPath);
                if (_runConfig == null)
                {
                    //给请求方应答
                    NotifyTaskErr("金沙引擎：工作项外部配置文件加载失败，文件解析失败！", 8);
                    return default(T);
                }
                return _runConfig;
            }
            NotifyTaskErr("金沙引擎：工作项外部配置文件加载失败，文件不存在！", 8);
            return default(T);
        }

        
    }
}
